import java.io.*;
import java.net.Socket;

public class Seeder extends Thread
{

	private Socket socket;
	private OutputStream outB;
	private String key;
	private byte[] byteFile;

	public Seeder(Socket s)
	{
		super();
		this.socket = s;
	}


	public void run()
	{
		
		try
		{
			outB = this.socket.getOutputStream();
		
			/*
				Receive "interested $key"
				Envoyer "have $key $bufferMap"
			
				Receive "getpieces"
				Envoie les pieces demandées
			*/


			// Receive "interested $key"
			String str = this.receiveFromLeecher();
			this.key = str.substring(11, str.length());
			String haveSend = "have "+this.key+" ";
		
			// Envoie de "have $key $bufferMap"
			outB.write(haveSend.getBytes());
			outB.write(Bdd.SEED_MAP.get(this.key).getBufferMap());
			outB.write("\n".getBytes());
			this.sendToLeecherByte();
			
			// Receive "getpieces $key [i1 ... in]"
			String str2 = this.receiveFromLeecher();
			String list_index_str = str2.substring(44, str2.length()-1);
			String list_index[] = list_index_str.split(" ");
			
			// Envoie de "data $key [i1:p1 ...]"
			String dataSend = "data "+this.key+" [";
			outB.write(dataSend.getBytes());
			File f = new File(Config.DIR_SEED+"/"+Bdd.SEED_MAP.get(this.key).getName());
			this.byteFile = this.getBytesFromFile(f);
			this.buildDataByte(list_index);
			this.sendToLeecherByte();
			
		}
		catch (IOException ex) { }
	}
	
	
	private void buildDataByte(String list_index[]) throws IOException
	{
		for(int i=0; i<list_index.length-1; i++)
			this.buildPartDataByte(list_index[i], false);
		this.buildPartDataByte(list_index[list_index.length-1], true);
		
		outB.write("]\n".getBytes());
	}
	
	
	private void buildPartDataByte(String id, Boolean last) throws IOException
	{
		outB.write(id.getBytes());
		outB.write(":".getBytes());
		
		byte[] bytes = new byte[Bdd.ON_TRACKER.get(this.key).getSizePieces()];

		int start = bytes.length*Integer.parseInt(id);
		int end = start+bytes.length;
		for(int i = start; i<end; i++)
			bytes[i-start] = this.byteFile[i];

		
		outB.write(bytes);
		
		if(!last)
			outB.write(" ".getBytes());
	}
	
	
	private void sendToLeecherByte()
	{
		if(this.socket == null || !this.socket.isConnected())
		{
			System.out.println("Socket not connected.");
			return;
		}

		Tools.traceFluxSend("seeder : Bytes");
		
		try{
			this.outB.flush();
		}
		catch (IOException ex) { }
	}
	


	private String receiveFromLeecher()
	{
		if(this.socket == null || !this.socket.isConnected())
		{
			System.out.println("Socket not connected.");
			return null;
		}

		try{
			BufferedReader receive_s = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
			String str = receive_s.readLine();
			Tools.traceFluxReceive("seeder : "+str);
			return str;
		}catch(IOException e){ return null; }
	}
	
	
	// Returns the contents of the file in a byte array.
	public byte[] getBytesFromFile(File file) throws IOException 
	{
		InputStream is = new FileInputStream(file);

		// Get the size of the file
		long length = file.length();

		// You cannot create an array using a long type.
		// It needs to be an int type.
		// Before converting to an int type, check
		// to ensure that file is not larger than Integer.MAX_VALUE.
		if (length > Integer.MAX_VALUE) {
		    // File is too large
		}

		// Create the byte array to hold the data
		byte[] bytes = new byte[(int)length];

		// Read in the bytes
		int offset = 0;
		int numRead = 0;
		while (offset < bytes.length
		       && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
		    offset += numRead;
		}

		// Ensure all the bytes have been read in
		if (offset < bytes.length) {
		    throw new IOException("Could not completely read file "+file.getName());
		}

		// Close the input stream and return bytes
		is.close();
		return bytes;
	}

}

